<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace Hyperfx\Framework\Exception\Handler;

use Hyperfx\Framework\Constants\ErrorCode;
use Hyperf\Grpc\StatusCode;
use Psr\Log\LogLevel;
use Hyperf\GrpcServer\Exception\GrpcException;
use Throwable;

trait BaseExceptionHandler {

    // 日志映射级别
    private static $LOG_LEVEL_MAPPING = [
        // rpc
        StatusCode::CANCELLED => LogLevel::ERROR,
        StatusCode::UNKNOWN => LogLevel::ERROR,
        StatusCode::INVALID_ARGUMENT => LogLevel::WARNING,
        StatusCode::DEADLINE_EXCEEDED => LogLevel::ERROR,
        StatusCode::NOT_FOUND => LogLevel::INFO,
        StatusCode::ALREADY_EXISTS => LogLevel::INFO,
        StatusCode::PERMISSION_DENIED => LogLevel::NOTICE,
        StatusCode::RESOURCE_EXHAUSTED => LogLevel::ERROR,
        StatusCode::FAILED_PRECONDITION => LogLevel::ERROR,
        StatusCode::ABORTED => LogLevel::ERROR,
        StatusCode::OUT_OF_RANGE => LogLevel::WARNING,
        StatusCode::UNIMPLEMENTED => LogLevel::ALERT,
        StatusCode::INTERNAL => LogLevel::ALERT,
        StatusCode::UNAVAILABLE => LogLevel::ALERT,
        StatusCode::DATA_LOSS => LogLevel::ALERT,
        StatusCode::UNAUTHENTICATED => LogLevel::NOTICE,

        // api
        ErrorCode::INVALID_ARGUMENT => LogLevel::WARNING,
        ErrorCode::UNAUTHENTICATED => LogLevel::NOTICE,
        ErrorCode::PERMISSION_DENIED => LogLevel::NOTICE,
        ErrorCode::NOT_FOUND => LogLevel::INFO,
        ErrorCode::ALREADY_EXISTS => LogLevel::INFO,
        ErrorCode::SERVER_ERROR => LogLevel::ALERT,
        501 => LogLevel::ALERT,
        503 => LogLevel::ALERT,
    ];

    public function geCode(Throwable $throwable, int $code = 0): int {
        if ($code == 0) {
            $code = $throwable->getCode();
        }
        if ($code == 0) {
            if ($throwable instanceof \InvalidArgumentException) {
                $code = ErrorCode::INVALID_ARGUMENT;
            }
        }
        return (int) $code;
    }

    public function getLogLevel(Throwable $throwable, int $code = 0): string {
        if ($code == 0) {
            $code = $throwable->getCode();
        }

        if ($code > 600) {
            $code = (int) substr((string) $code, 0, 3);
        }

        $logLevel = self::$LOG_LEVEL_MAPPING[$code] ?? '';

        if (empty($logLevel)) {
            if ($throwable instanceof \ErrorException) {
                // 通常指语法错误
                $logLevel = LogLevel::ERROR;

            } else if ($throwable instanceof GrpcException) {
                $logLevel = LogLevel::ERROR;

            } else if ($throwable instanceof \LogicException) {
                $logLevel = LogLevel::ERROR;

            } else {
                $logLevel = LogLevel::ALERT;
            }
        }

        return $logLevel;
    }
}
